(load "prelude.ss")
(load "17.we-change-we-are.ss")

;; Page 143
(define (lots m)
  (if (zero? m)
      '()
      (kons 'egg (lots (sub1 m)))))

(define (lenkth l)
  (if (null? l)
      0
      (add1 (lenkth (kdr l)))))

(define (add-at-end l)
  (cond ((null? (kdr l)) (konsC (kar l)
                                (konsC 'egg '())))
        (else (konsC (kar l)
                     (add-at-end (kdr l))))))

(define (add-at-end-too l)
  (letrec ((A (lambda (ls)
                (cond ((null? (kdr ls))
                       (set-kdr ls (kons 'egg '())))
                      (else (A (kdr ls)))))))
    (A l)
    l))

;; Page 143
(define (kons kar kdr)
  (lambda (selector) (selector kar kdr)))
(define (kar c) (c (lambda (a d) a)))
(define (kdr c) (c (lambda (a d) d)))

(define (bons kar)
  (let ((kdr '()))
   (lambda (selector)
     (selector (lambda (x) (set! kdr x))
               kar
               kdr))))

(define (set-kdr c x)
  ((c (lambda (s a d) s))
   x))

(define (kons a d)
  (let ((c (bons a)))
   (set-kdr c d)
   c))

(define (eklist? ls1 ls2)
  (cond ((null? ls1) (null? ls2))
        ((null? ls2) #f)
        (else (and (eq? (kar ls1) (kar ls2))
                   (eklist? (kdr ls1) (kdr ls2))))))

(define (same? c1 c2)
  (let ((t1 (kdr c1))
        (t2 (kdr c2)))
    (set-kdr c1 1)
    (set-kdr c2 2)
    (let ((v (= (kdr c1) (kdr c2))))
     (set-kdr c1 t1)
     (set-kdr c2 t2)
     v)))

;; Page 151
(define (last-kons ls)
  (lambda (ls)
    (cond ((null? (kdr ls) ls)
           (else (last-kons (kdr ls)))))))

(define (finite-lenkth p)
  (letcc infinite
         (letrec
           ((C (lambda (p q)
                 (cond
                   ((same? p q)
                    (infinite #f))
                   ((null? q) 0)
                   ((null? (kdr q)) 1)
                   (else
                     (+ (C (sl p) (qk q))
                        2)))))
            (qk (lambda (x) (kdr (kdr x))))
            (sl (lambda (x) (kdr x))))
           (cond
             ((null? p) 0)
             (else
               (add1 (C p (kdr p))))))))
